﻿using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace Red.Controls.Utils
{
    public class Helpers
    {
        public static T FindVisualAncestorOfType<T>( object element ) where T : DependencyObject
        {
            DependencyObject currrent = element as DependencyObject;
            while ( currrent != null )
            {
                var ancestor = currrent as T;
                if ( ancestor != null )
                {
                    return ancestor;
                }
                currrent = VisualTreeHelper.GetParent( currrent );
            }
            return null;
        }

        public static T FindFirstLogicalChild<T>( object element ) where T : DependencyObject
        {
            DependencyObject current = element as DependencyObject;
            if ( current != null )
            {
                IEnumerable logicalChildren = LogicalTreeHelper.GetChildren( current );
                foreach ( var child in logicalChildren )
                {
                    if ( child != null && child is T )
                    {
                        return (T)child;
                    }

                    T childItem = FindFirstLogicalChild<T>( child );
                    if ( childItem != null )
                    {
                        return childItem;
                    }
                }
            }

            return null;
        }

        public static T FindFirstVisualChild<T>( object element ) where T : DependencyObject
        {
            DependencyObject current = element as DependencyObject;
            if ( current != null )
            {
                for ( int i = 0; i < VisualTreeHelper.GetChildrenCount( current ); ++i )
                {
                    DependencyObject child = VisualTreeHelper.GetChild( current, i );
                    if ( child != null && child is T )
                    {
                        return (T)child;
                    }

                    T childItem = FindFirstVisualChild<T>( child );
                    if ( childItem != null )
                    {
                        return childItem;
                    }
                }
            }

            return null;
        }

        public static void RefreshBindingValues( FrameworkElement element, DependencyProperty dependencyProperty )
        {
            BindingExpression bindingExpression = element.GetBindingExpression( dependencyProperty );
            bindingExpression?.UpdateSource();
        }

        /// <summary>
        /// This function will run the associated validation rules on the specified element
        /// </summary>
        /// <returns><see langword="true"/> if the element passes all validation rules</returns>
        public static bool ValidateElement( FrameworkElement element )
        {
            int numErrors = Validation.GetErrors( element ).Count;
            return numErrors == 0;
        }

        /// <summary>
        /// This will clear the error state for the specified element
        /// </summary>
        /// <seealso cref="ValidateElement"/>
        public static void ClearElementValidation( FrameworkElement element, DependencyProperty dependencyProperty )
        {
            Validation.ClearInvalid( element.GetBindingExpression( dependencyProperty ) );
        }

        /// <summary>
        ///     Cleans separators on a list so that:
        ///     a) trailing separators are hidden
        ///     b) there's never two or more separators in a row
        /// </summary>
        public static void CleanupSeparators( ItemCollection items )
        {
            bool prevWasSep = false;
            for ( int i = 0; i < items.Count; ++i )
            {
                var sep = items[i] as Separator;
                if ( sep != null )
                {
                    if ( prevWasSep )
                        items.RemoveAt( i );
                    prevWasSep = true;
                }
                else
                {
                    var elem = items[i] as UIElement;
                    if ( elem != null && elem.Visibility == Visibility.Visible )
                        prevWasSep = false;
                }
            }

            bool wasVisible = false;
            for ( int i = 0; i < items.Count; ++i )
                if ( HandleTrailingSeparators( items[i], ref wasVisible ) )
                    break;

            wasVisible = false;
            for ( int i = items.Count - 1; i >= 0; --i )
                if ( HandleTrailingSeparators( items[i], ref wasVisible ) )
                    break;
        }

        private static bool HandleTrailingSeparators( object item, ref bool wasVisible )
        {
            var elem = item as UIElement;
            if ( elem != null )
            {
                if ( elem is Separator )
                { // the idea is to hide leading/trailing separators, not to remove them - so they show up once they are not trailing anymore
                    elem.Visibility = wasVisible ? Visibility.Visible : Visibility.Collapsed;
                    return true; // break
                }

                wasVisible |= ( elem.Visibility == Visibility.Visible );
            }

            return false;
        }
    }
}